#pragma once

#include "MetroClass.h"

using namespace Platform;
using namespace Windows::Storage;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;

namespace mbase {

ref class Value abstract {
public:
	virtual int asInt()=0;
	virtual float asFloat()=0;
	virtual String^ asString()=0;
	virtual MetroClass^ asObject()=0;
	//virtual Value^ operator+(Value^ v)=0;
	virtual Value^ operator==(Value^ v)=0;
	virtual Value^ operator!=(Value^ v)=0;
	virtual Value^ operator<(Value^ v)=0;
	virtual Value^ operator>(Value^ v)=0;
	virtual Value^ operator<=(Value^ v)=0;
	virtual Value^ operator>=(Value^ v)=0;
	virtual Value^ operator!()=0;
	virtual Value^ operator&&(Value^ v)=0;
	virtual Value^ operator||(Value^ v)=0;
};

ref class IntValue : Value {
private:
	int n;
public:
	IntValue(int _n) : n(_n) {}
	int asInt() { return n; }
	float asFloat() { return n; }
	String^ asString() { std::wstringstream ss; ss << n; return ref new String(ss.str().c_str()); }
	MetroClass^ asObject() { return nullptr; }
	//Value^ operator+(Value^ v) { return ref new IntValue(n + v->asInt()); }
	Value^ operator==(Value^ v) { return ref new IntValue(n == v->asInt() ? 1 : 0); }
	Value^ operator!=(Value^ v) { return ref new IntValue(n != v->asInt() ? 1 : 0); }
	Value^ operator<(Value^ v) { return ref new IntValue(n < v->asInt() ? 1 : 0); }
	Value^ operator>(Value^ v) { return ref new IntValue(n > v->asInt() ? 1 : 0); }
	Value^ operator<=(Value^ v) { return ref new IntValue(n <= v->asInt() ? 1 : 0); }
	Value^ operator>=(Value^ v) { return ref new IntValue(n >= v->asInt() ? 1 : 0); }
	Value^ operator!() { return ref new IntValue(n != 0 ? 0 : 1); }
	Value^ operator&&(Value^ v) { return ref new IntValue(n != 0 && v->asInt() != 0 ? 1 : 0); }
	Value^ operator||(Value^ v) { return ref new IntValue(n != 0 || v->asInt() != 0 ? 1 : 0); }
};

ref class FltValue : Value {
private:
	float n;
public:
	FltValue(float _n) : n(_n) {}
	int asInt() { return n; }
	float asFloat() { return n; }
	String^ asString() { std::wstringstream ss; ss << n; return ref new String(ss.str().c_str()); }
	MetroClass^ asObject() { return nullptr; }
	//Value^ operator+(Value^ v) { return ref new FltValue(n + v->asFloat()); }
	Value^ operator==(Value^ v) { return ref new IntValue(n == v->asFloat() ? 1 : 0); }
	Value^ operator!=(Value^ v) { return ref new IntValue(n != v->asFloat() ? 1 : 0); }
	Value^ operator<(Value^ v) { return ref new IntValue(n < v->asFloat() ? 1 : 0); }
	Value^ operator>(Value^ v) { return ref new IntValue(n > v->asFloat() ? 1 : 0); }
	Value^ operator<=(Value^ v) { return ref new IntValue(n <= v->asFloat() ? 1 : 0); }
	Value^ operator>=(Value^ v) { return ref new IntValue(n >= v->asFloat() ? 1 : 0); }
	Value^ operator!() { return ref new IntValue(n != 0 ? 0 : 1); }
	Value^ operator&&(Value^ v) { return ref new IntValue(n != 0 && v->asInt() != 0 ? 1 : 0); }
	Value^ operator||(Value^ v) { return ref new IntValue(n != 0 || v->asInt() != 0 ? 1 : 0); }
};

ref class StringValue : Value {
private:
	String^ s;
public:
	StringValue(String^ _s) : s(_s) {}
	int asInt() { return _wtoi(s->Data()); }
	float asFloat() { return asInt(); }
	String^ asString() { return s; }
	MetroClass^ asObject() { return nullptr; }
	//Value^ operator+(Value^ v) { return ref new StringValue(s + v->asString()); }
	Value^ operator==(Value^ v) { return ref new IntValue(s == v->asString() ? 1 : 0); }
	Value^ operator!=(Value^ v) { return ref new IntValue(s != v->asString() ? 1 : 0); }
	Value^ operator<(Value^ v) { return ref new IntValue(s < v->asString() ? 1 : 0); }
	Value^ operator>(Value^ v) { return ref new IntValue(s > v->asString() ? 1 : 0); }
	Value^ operator<=(Value^ v) { return ref new IntValue(s <= v->asString() ? 1 : 0); }
	Value^ operator>=(Value^ v) { return ref new IntValue(s >= v->asString() ? 1 : 0); }
	Value^ operator!() { return ref new IntValue(s != nullptr ? 0 : 1); }
	Value^ operator&&(Value^ v) { return ref new IntValue(s != nullptr && v->asString() != nullptr ? 1 : 0); }
	Value^ operator||(Value^ v) { return ref new IntValue(s != nullptr || v->asString() != nullptr ? 1 : 0); }
};

ref class ObjectValue : Value {
private:
	MetroClass^ object;
public:
	ObjectValue(MetroClass^ obj) : object(obj) {}
	int asInt() { return 0; }
	float asFloat() { return 0; }
	String^ asString() { return object->GetClassName(); }
	MetroClass^ asObject() { return object; }
	//Value^ operator+(Value^ v) { return ref new ObjectValue(nullptr); }
	Value^ operator==(Value^ v) { return ref new IntValue(object == v->asObject() ? 1 : 0); }
	Value^ operator!=(Value^ v) { return ref new IntValue(object == v->asObject() ? 0 : 1); }
	Value^ operator<(Value^ v) { return ref new IntValue(0); }
	Value^ operator>(Value^ v) { return ref new IntValue(0); }
	Value^ operator<=(Value^ v) { return ref new IntValue(0); }
	Value^ operator>=(Value^ v) { return ref new IntValue(0); }
	Value^ operator!() { return ref new IntValue(object != nullptr ? 0 : 1); }
	Value^ operator&&(Value^ v) { return ref new IntValue(object != nullptr && v->asObject() != nullptr ? 1 : 0); }
	Value^ operator||(Value^ v) { return ref new IntValue(object != nullptr || v->asObject() != nullptr ? 1 : 0); }
};

}
